﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="DiplomProjectController.cs" company="">
//   Copyright (c) 2010/2011 All Right Reserved
// </copyright>
// <summary>
//   Contains DiplomProjectController class declaration.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace IBupro.Controllers
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using IBupro.Classes;
    using IBupro.Controllers.Classes;
    using IBupro.Models;
    using IBupro.Models.DiplomProject;
    using iBuproModel;
    using iBuproModel.Repositories.Interfaces;

    /// <summary>
    /// This controller contains actions related to diplom project.
    /// </summary>
    public class DiplomProjectController : CustomController
    {
        private IDiplomProjectRepository repository;

        /// <summary>
        /// Inits controller
        /// </summary>
        public DiplomProjectController()
        {
            this.repository = repositoryService.DiplomProjectRepositoryCreateInstance();
        }


        /// <summary>
        /// Lists All diplom projects
        /// </summary>
        /// <returns></returns>
        public ActionResult Index()
        {
            if (this.User.IsInRole("Admin")) return this.View(this.repository.GetAll().ToList());
            else if (User.IsInRole("Principal"))
            {
                return RedirectToAction("Index", "Principal");
            }
            else if (User.IsInRole("Lector"))
            {
                return RedirectToAction("Index", "Lector");
            }
            else return RedirectToAction("DiplomProjects", "Search");
        }

        [Authorize(Roles = "Admin,Lector,Principal")]
        public ActionResult Create()
        {
            DiplomProjectLectorModel model = new DiplomProjectLectorModel();
            model.Literature = "Dodá vedoucí práce";

            return View(model);
        }

        /// <summary>
        /// Created a diplom project from model
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        [HttpPost]
        [Authorize(Roles = "Admin,Lector,Principal")]
        public ActionResult Create(DiplomProjectLectorModel model)
        {
            try
            {
                if (ModelState.IsValid)
                {
                    IUserRepository userRepository = repositoryService.UserRepositoryCreateInstance();
                    User user = userRepository.GetUserByUserName(User.Identity.Name);

                    ISubjectRepository subjectRepository = repositoryService.SubjectRepositoryCreateInstace();
                    IDiplomProjectTypeRepository diplomprojectTypeRepository =
                        repositoryService.DiplomProjectTypeRepositoryCreateInstance();

                    IDiplomProjectRepository diplomProjectRepository =
                        repositoryService.DiplomProjectRepositoryCreateInstance();
                    ITagRepository tagRepository = repositoryService.TagRepositoryCreateInstance();
                    IDepartmentRepository departments = repositoryService.DepartmentRepositoryCreateInstance();

                    DiplomProject project = new DiplomProject();

                    project.Approved = false;
                    project.Created = DateTime.Now;
                    project.DepartmentPrincipal =
                        departments.First(d => d.Id == model.DepartmentId).DepartmentPrincipal.First();
                    project.Name = model.Name;
                    project.Shortcut = model.Shortcut;
                    project.DiplomProjectType = diplomprojectTypeRepository.First(t => t.Id == model.ProjectTypeId);
                    project.Detail = model.Detail;
                    project.Lector = user;
                    project.Principal = user;
                    project.Department = departments.First(d => d.Id == model.DepartmentId);
                    project.Literature = model.Literature;

                    IDiplomProjectStateRepository projectState =
                        repositoryService.DiplomProjectStateRepositoryCreateInstance();

                    project.DiplomProjectState = projectState.GetNewProjectState();


                    tagRepository.SaveTagsForProject(model.Tags, project);

                    user.LectorDiplomProjects.Add(project);


                    diplomProjectRepository.AddDiplomProjectForLector(user, project);

                    diplomProjectRepository.SaveChanges();

                    FlashMessenger.AddMessage(
                        Translator.Instance["diplomProjectSuccessfullyCreated"], MessageType.Success);
                }
                else
                {
                    IUserRepository userRepository = repositoryService.UserRepositoryCreateInstance();
                    iBuproModel.User user = userRepository.GetUserByUserName(User.Identity.Name);
                    ISubjectRepository subjectRepository = repositoryService.SubjectRepositoryCreateInstace();
                    IDepartmentRepository departments = repositoryService.DepartmentRepositoryCreateInstance();
                    IDiplomProjectTypeRepository diplomprojectTypeRepository =
                        repositoryService.DiplomProjectTypeRepositoryCreateInstance();

                    FlashMessenger.AddMessage(Translator.Instance["diplomProjectNotCreated"], MessageType.Error);
                    model.Tags.ToList().Clear();
                    return View(model);
                }

                return RedirectToAction("Index");
            }
            catch
            {
                return View(model);
            }
        }


        [Authorize(Roles = "Admin,Lector,Principal")]
        public ActionResult Edit(int id)
        {
            IUserRepository userRepository = repositoryService.UserRepositoryCreateInstance();
            ISubjectRepository subjectRepository = repositoryService.SubjectRepositoryCreateInstace();
            IDiplomProjectTypeRepository projectTypeRepository =
                repositoryService.DiplomProjectTypeRepositoryCreateInstance();
            IDiplomProjectRepository diplomprojectRepository = repositoryService.DiplomProjectRepositoryCreateInstance();
            ITagRepository tagRepository = repositoryService.TagRepositoryCreateInstance();
            IDepartmentRepository departments = repositoryService.DepartmentRepositoryCreateInstance();


            DiplomProjectLectorModel model = new DiplomProjectLectorModel();

            DiplomProject storedProject = diplomprojectRepository.First(p => p.Id == id);

            iBuproModel.User user = userRepository.GetUserByUserName(User.Identity.Name);

            if (User.IsInRole("Lector") &&
                user.LectorDiplomProjects.Contains(diplomprojectRepository.First(p => p.Id == id)) == false)
            {
                throw new Exception("You cannot project which is not yours");
            }

            model.Detail = storedProject.Detail;
            model.Name = storedProject.Name;
            model.Shortcut = storedProject.Shortcut;
            model.ProjectTypeId = storedProject.DiplomProjectType.Id;
            model.Tags = tagRepository.GetTagStringForProject(storedProject);
            model.DepartmentId = storedProject.Department.Id;
            model.Literature = storedProject.Literature;

            return View(model);
        }


        /// <summary>
        /// Edits diplom project according model
        /// </summary>
        /// <param name="id"></param>
        /// <param name="model"></param>
        /// <returns></returns>
        [Authorize(Roles = "Admin,Lector,Principal")]
        [HttpPost]
        public ActionResult Edit(int id, DiplomProjectLectorModel model)
        {
            try
            {
                if (ModelState.IsValid)
                {
                    IUserRepository userRepository = repositoryService.UserRepositoryCreateInstance();
                    ISubjectRepository subjectRepository = repositoryService.SubjectRepositoryCreateInstace();
                    IDiplomProjectTypeRepository diplomprojectTypeRepository =
                        repositoryService.DiplomProjectTypeRepositoryCreateInstance();
                    ITagRepository tagRepository = repositoryService.TagRepositoryCreateInstance();
                    IDiplomProjectRepository diplomProjectRepository =
                        repositoryService.DiplomProjectRepositoryCreateInstance();
                    IDepartmentRepository departments = repositoryService.DepartmentRepositoryCreateInstance();


                    DiplomProject project = diplomProjectRepository.First(p => p.Id == id);

                    iBuproModel.User user = userRepository.GetUserByUserName(User.Identity.Name);

                    if (User.IsInRole("Lector") &&
                        user.LectorDiplomProjects.Contains(diplomProjectRepository.First(p => p.Id == id)) == false)
                    {
                        throw new Exception("You cannot modify project which is not yours");
                    }

                    project.Name = model.Name;
                    project.Shortcut = model.Shortcut;
                    project.DepartmentPrincipal =
                        departments.First(d => d.Id == model.DepartmentId).DepartmentPrincipal.First();
                    project.DiplomProjectType = diplomprojectTypeRepository.First(t => t.Id == model.ProjectTypeId);
                    project.Detail = model.Detail;
                    project.Department = departments.First(d => d.Id == model.DepartmentId);
                    project.Literature = model.Literature;

                    diplomProjectRepository.UpdateDimplomProject(id, project);
                    tagRepository.UpdateTagsForProject(model.Tags, project.Id);

                    diplomProjectRepository.SaveChanges();
                }
                else
                {
                    IUserRepository userRepository = repositoryService.UserRepositoryCreateInstance();
                    iBuproModel.User user = userRepository.GetUserByUserName(User.Identity.Name);
                    ISubjectRepository subjectRepository = repositoryService.SubjectRepositoryCreateInstace();
                    IDepartmentRepository departments = repositoryService.DepartmentRepositoryCreateInstance();
                    IDiplomProjectTypeRepository diplomprojectTypeRepository =
                        repositoryService.DiplomProjectTypeRepositoryCreateInstance();


                    return View(model);
                }

                return RedirectToAction("Index");
            }
            catch
            {
                return View(model);
            }
        }


        /// <summary>
        /// Delets diplom project
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [Authorize(Roles = "Admin,Lector,Principal")]
        public ActionResult Delete(int id)
        {
            IUserRepository userRepository = repositoryService.UserRepositoryCreateInstance();
            iBuproModel.User user = userRepository.GetUserByUserName(User.Identity.Name);

            IDiplomProjectRepository diplomProjectRepository = repositoryService.DiplomProjectRepositoryCreateInstance();

            DiplomProject project = diplomProjectRepository.First(p => p.Id == id);

            if (User.IsInRole("Lector") &&
                user.LectorDiplomProjects.Contains(diplomProjectRepository.First(p => p.Id == id)) == false)
            {
                throw new Exception("You cannot modify project which is not yours");
            }

            diplomProjectRepository.DeleteDiplomProject(project.Id);


            diplomProjectRepository.SaveChanges();

            return RedirectToAction("Index");
        }


        /// <summary>
        /// Lists detail of diplom project
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public ActionResult Details(int id)
        {
            return this.View(this.repository.First(p => p.Id == id));
        }


        /// <summary>
        /// Partial View for diplom project detail
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public ActionResult PartialDetail(int id)
        {
            return this.View(this.repository.First(p => p.Id == id));
        }


        /// <summary>
        /// Subscribes looged in user into diplom project
        /// </summary>
        /// <param name="id">Id of project</param>
        /// <returns></returns>
        [Authorize(Roles = "Student")]
        public ActionResult Subscribe(int id)
        {
            IUserRepository userRepository = repositoryService.UserRepositoryCreateInstance();
            iBuproModel.User user = userRepository.GetUserByUserName(User.Identity.Name);

            IDiplomProjectStateRepository projectState = repositoryService.DiplomProjectStateRepositoryCreateInstance();

            DiplomProject diplomProject = this.repository.First(p => p.Id == id);
            projectState.SetBookedProjectState(diplomProject);

            user.StudentDiplomProjects.Add(diplomProject);

            userRepository.SaveChanges();


            FlashMessenger.AddMessage(
                IBupro.Classes.Translator.Instance["subscribedToDiplomProject"] + diplomProject.Name,
                IBupro.Classes.MessageType.Success);

            string projectLeaderInformations = diplomProject.Lector.FirstName + " " + diplomProject.Lector.LastName +
                                               ", " + diplomProject.Lector.Email;
            FlashMessenger.AddMessage(
                Translator.Instance["makeAppointmentWithProjectLector"] + " " + projectLeaderInformations,
                MessageType.Notice);

            mailer.ProjectHasBeenBooked(diplomProject, user);
            return RedirectToAction("Index", "Student");
        }


        /// <summary>
        /// This method denies diplom project from lector role
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [Authorize(Roles = "Lector")]
        public ActionResult LectorDenyDiplomProject(int id)
        {
            IUserRepository userRepository = repositoryService.UserRepositoryCreateInstance();

            IDiplomProjectRepository diplomProjectRepository = repositoryService.DiplomProjectRepositoryCreateInstance();
            IDiplomProjectStateRepository projectState = repositoryService.DiplomProjectStateRepositoryCreateInstance();

            DiplomProject project = diplomProjectRepository.First(p => p.Id == id);

            if (project.Lector.Id != userRepository.GetUserByUserName(User.Identity.Name).Id)
            {
                throw new Exception("Cannot modify project which is not yours.");
            }

            projectState.SetNewProjectState(project);
            projectState.SaveChanges();

            FlashMessenger.AddMessage("Project participation has been denied", MessageType.Notice);

            return RedirectToAction("Index", "Lector");
        }

        [Authorize(Roles = "Lector")]
        public ActionResult LectorAcceptDiplomProject(int id)
        {
            AcceptDiplomProjectModel model = new AcceptDiplomProjectModel();
            IDiplomProjectRepository projectRepository = repositoryService.DiplomProjectRepositoryCreateInstance();

            DiplomProject project = projectRepository.First(p => p.Id == id);

            model.DiplomProject = project;


            return View();
        }


        /// <summary>
        /// Accepts DiplomProject for lector
        /// </summary>
        /// <param name="id">id of diplom project</param>
        /// <returns></returns>
        [Authorize(Roles = "Lector")]
        [HttpPost]
        public ActionResult LectorAcceptDiplomProject(int id, AcceptDiplomProjectModel model)
        {
            IUserRepository userRepository = repositoryService.UserRepositoryCreateInstance();
            if (model.newMessage == null)
                model.newMessage = "";

            IDiplomProjectRepository diplomProjectRepository = repositoryService.DiplomProjectRepositoryCreateInstance();

            IDiplomProjectStateRepository projectState = repositoryService.DiplomProjectStateRepositoryCreateInstance();
            IHistoryRepository historyRepository = repositoryService.HistoryRepositoryCreateInstance();
            DiplomProject project = diplomProjectRepository.First(p => p.Id == id);

            if (project.Lector.Id != userRepository.GetUserByUserName(User.Identity.Name).Id)
            {
                throw new Exception("Cannot modify project which is not yours.");
            }


            historyRepository.AddMessage(id, User.Identity.Name, model.newMessage);


            projectState.SetLectorAcceptedState(project);
            projectState.SaveChanges();

            FlashMessenger.AddMessage(
                "Project " + project.Name + " has beem send to department principal " +
                project.Department.DepartmentPrincipal.First().FirstName + " " +
                project.Department.DepartmentPrincipal.First().LastName,
                MessageType.Notice);

            mailer.ProjectHasBeenAcceptedByLector(project, model.newMessage);
            return RedirectToAction("Index", "Lector");
        }


        [Authorize(Roles = "Principal")]
        public ActionResult PrincipalAcceptDiplomProject(int id)
        {
            IUserRepository userRepository = repositoryService.UserRepositoryCreateInstance();

            IDiplomProjectRepository diplomProjectRepository = repositoryService.DiplomProjectRepositoryCreateInstance();
            IDiplomProjectStateRepository projectState = repositoryService.DiplomProjectStateRepositoryCreateInstance();

            DiplomProject project = diplomProjectRepository.First(p => p.Id == id);

            if (project.DepartmentPrincipal.Id != userRepository.GetUserByUserName(User.Identity.Name).Id)
            {
                throw new Exception("Cannot modify project which is not yours.");
            }

            projectState.SetSubscribedState(project);
            projectState.SaveChanges();

            FlashMessenger.AddMessage("Project " + project.Name + " has beem accepted.", MessageType.Notice);
            mailer.ProjectHasBeenAcceptedByPrincipal(project);

            return RedirectToAction("Index", "Principal");
        }

        public ActionResult PrincipalDenytDiplomProject(int id)
        {
            AcceptDiplomProjectModel model = new AcceptDiplomProjectModel();
            IDiplomProjectRepository projectRepository = repositoryService.DiplomProjectRepositoryCreateInstance();

            DiplomProject project = projectRepository.First(p => p.Id == id);

            model.DiplomProject = project;

            return View();
        }

        /// <summary>
        /// Denies diplom project from principal role
        /// </summary>
        /// <param name="id"></param>
        /// <param name="model"></param>
        /// <returns></returns>
        [Authorize(Roles = "Principal")]
        [HttpPost]
        public ActionResult PrincipalDenytDiplomProject(int id, AcceptDiplomProjectModel model)
        {
            IUserRepository userRepository = repositoryService.UserRepositoryCreateInstance();
            if (model.newMessage == null)
                model.newMessage = "";

            if (userRepository.First(p => p.Id == id) == null)
            {
                throw new Exception("Cannot modify project which is not yours.");
            }

            IDiplomProjectRepository diplomProjectRepository = repositoryService.DiplomProjectRepositoryCreateInstance();
            IDiplomProjectStateRepository projectState = repositoryService.DiplomProjectStateRepositoryCreateInstance();
            IHistoryRepository history = repositoryService.HistoryRepositoryCreateInstance();

            DiplomProject project = diplomProjectRepository.First(p => p.Id == id);

            if (project.DepartmentPrincipal.Id != userRepository.GetUserByUserName(User.Identity.Name).Id)
            {
                throw new Exception("Cannot modify project which is not yours.");
            }

            history.AddMessage(id, User.Identity.Name, model.newMessage);

            projectState.SetBookedProjectState(project);
            projectState.SaveChanges();

            FlashMessenger.AddMessage("Project " + project.Name + " has beem denied.", MessageType.Notice);
            mailer.ProjectHasBeenDeniedByPrincipal(project, model.newMessage);


            return RedirectToAction("Index", "Principal");
        }

        /// <summary>
        /// Action method for partial view AcceptDenyDiplomProject
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public ActionResult AcceptDenyDiplomProjectPartial(int id)
        {
            DiplomProject project = repository.First(p => p.Id == id);
            return View(project);
        }

        /// <summary>
        /// Action method for partial view DefendCancelDiplomProject
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public ActionResult DefendCancelDiplomProjectPartial(int id)
        {
            DiplomProject project = repository.First(p => p.Id == id);
            return View(project);
        }


        /// <summary>
        /// Sets project to canceled state and moves it to archive
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public ActionResult LectorDenyDiplmoProjectArchive(int id)
        {
            IUserRepository userRepository = repositoryService.UserRepositoryCreateInstance();

            IDiplomProjectRepository diplomProjectRepository = repositoryService.DiplomProjectRepositoryCreateInstance();
            IDiplomProjectStateRepository projectState = repositoryService.DiplomProjectStateRepositoryCreateInstance();

            DiplomProject project = diplomProjectRepository.First(p => p.Id == id);

            if (project.Lector.Id != userRepository.GetUserByUserName(User.Identity.Name).Id)
            {
                throw new Exception("Cannot modify project which is not yours.");
            }

            //projectState.SetCanceledState(project);
            project.DiplomProjectState = projectState.GetCanceledProjectState();
            diplomProjectRepository.SaveChanges();

            FlashMessenger.AddMessage("Project participation has been denied", MessageType.Notice);
            FlashMessenger.AddMessage("Project has been moved to archive", MessageType.Notice);

            return RedirectToAction("Archive", "DiplomProject");
        }


        /// <summary>
        /// Sets project to defended state
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public ActionResult LectorDefendedDiplmoProjectArchive(int id)
        {
            IUserRepository userRepository = repositoryService.UserRepositoryCreateInstance();

            IDiplomProjectRepository diplomProjectRepository = repositoryService.DiplomProjectRepositoryCreateInstance();
            IDiplomProjectStateRepository projectState = repositoryService.DiplomProjectStateRepositoryCreateInstance();

            DiplomProject project = diplomProjectRepository.First(p => p.Id == id);

            if (project.Lector.Id != userRepository.GetUserByUserName(User.Identity.Name).Id)
            {
                throw new Exception("Cannot modify project which is not yours.");
            }

            //projectState.SetCanceledState(project);
            projectState.SetDefendedState(project);
            diplomProjectRepository.SaveChanges();

            FlashMessenger.AddMessage("Project participation has been defended", MessageType.Success);
            FlashMessenger.AddMessage("Project has been moved to archive", MessageType.Notice);

            return RedirectToAction("Archive", "DiplomProject");
        }

        /// <summary>
        /// Returns list of archived projects
        /// </summary>
        /// <returns></returns>
        public ActionResult ListArchivedProjects()
        {
            IDiplomProjectStateRepository projectStates = repositoryService.DiplomProjectStateRepositoryCreateInstance();
            IDiplomProjectRepository projects = repositoryService.DiplomProjectRepositoryCreateInstance();
            IUserRepository users = repositoryService.UserRepositoryCreateInstance();

            User user = users.GetUserByUserName(User.Identity.Name);

            List<DiplomProject> result = new List<DiplomProject>();

            if (User.IsInRole("Lector"))
            {
                result.AddRange(
                    user.LectorDiplomProjects.Where(
                        p => p.DiplomProjectState == projectStates.GetCanceledProjectState() ||
                             p.DiplomProjectState == projectStates.GetSubscribedProjectState() ||
                             p.DiplomProjectState == projectStates.GetDefendedProjectState()));
            }
            if (User.IsInRole("Principal"))
            {
                List<DiplomProject> principalArchive =
                    user.DepartmentPrincipalDiplomProjects.Where(
                        p => p.DiplomProjectState == projectStates.GetCanceledProjectState() ||
                             p.DiplomProjectState == projectStates.GetSubscribedProjectState() ||
                             p.DiplomProjectState == projectStates.GetDefendedProjectState()).ToList();

                foreach (DiplomProject prj in principalArchive)
                {
                    if (!result.Contains(prj))
                    {
                        result.Add(prj);
                    }
                }
            }

            return View(result);
        }

        public ActionResult Archive()
        {
            return View();
        }
    }
}